package org.smartcti.freeswitch.inbound.internal;

import java.io.IOException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.smartcti.freeswitch.inbound.event.DisconnectEvent;
import org.smartcti.freeswitch.inbound.event.InboundEvent;
import org.smartcti.freeswitch.inbound.response.CommandResponse;
import org.smartcti.freeswitch.util.SocketConnectionFacade;

public class InboundReaderImpl implements InboundReader {
	 private final EventBuilder eventBuilder;
	 private final ResponseBuilder responseBuilder;
	 private final Dispatcher dispatcher;
	 private SocketConnectionFacade socket;
	 private volatile boolean die = false;
	 private boolean dead = false;
	 private IOException terminationException;
	 private  final Logger logger = LogManager.getLogger(InboundReaderImpl.class);
	 
	 

	public InboundReaderImpl(final Dispatcher dispatcher) {
		super();
		this.eventBuilder = new EventBuilderImpl();
		this.responseBuilder = new ResponseBuilderImpl();
		this.dispatcher = dispatcher;
	}

	public void die() {
		this.die = true;
	}

	public IOException getTerminationException() {
		 return terminationException;
	}

	public boolean isDead() {
		 return dead;
	}

	public void setSocket(SocketConnectionFacade socket) {
		this.socket = socket;
	}

	public void run() {
		{
		final Map<String, String> buffer = new HashMap<String, String>();
		final Map<String, String> fragment = new HashMap<String, String>();
        String line;

        if (socket == null)
        {
            throw new IllegalStateException("Unable to run: socket is null.");
        }

        this.die = false;
        this.dead = false;

        try
        {
        	logger.debug("Begin read socket!");
        	int bufferLength = 0;
            // main loop
            while (!this.die && (line = socket.readLine()) != null)
            {
                if (line.length() > 0)
                {
                    int delimiterIndex;
                    int delimiterLength;

                    //delimiterIndex = line.indexOf(": ");
                    // begin of workaround for Astersik bug 13319
                    delimiterIndex = line.indexOf(" ");
                    delimiterLength = 1;
                    if (delimiterIndex > 0 && line.charAt(delimiterIndex - 1) == ':')
                    {
                        delimiterIndex--;
                        delimiterLength++;
                    }

                    if (delimiterIndex > 0 && line.length() > delimiterIndex + delimiterLength)
                    {
                        String name;
                        String value;

                        name = line.substring(0, delimiterIndex);
                        value = line.substring(delimiterIndex + delimiterLength);
                        
                        name = name.trim();
                        value = URLDecoder.decode(value.trim(),"UTF-8");

                        buffer.put(name, value);
                        // TODO tracing
                        logger.debug("Got name [" + name + "], value: [" + value + "]");
                    }
                    bufferLength +=(line.length()+1);
                    
                }


                // an empty line indicates a normal response's or event's end so we build
                // the corresponding value object and dispatch it through the ManagerConnection.
                if (line.length() == 0){
                	logger.debug("-------------------------");
                	bufferLength++;
                	 fragment.putAll(buffer);
                	 if(!buffer.containsKey("Content-Length")){
                		 if(fragment.containsKey("Content-Length")){
                			 final int contentLength = Integer.parseInt(fragment.get("Content-Length"));
                			 if(contentLength!=bufferLength){
                				 logger.error("Inbound Socket read error! contentLength:"+contentLength+"        bufferLength: "+bufferLength+" not supported!");
                			 }
                		 }
                		 final String contentType = fragment.get("Content-Type");
                		 if("command/reply".equals(contentType) || "api/response".equals(contentType)){
                     		CommandResponse response = buildResponse(fragment);
                             if (response != null)
                             {
                                 dispatcher.dispatchResponse(response);
                             }else{
                             	 logger.error("buildResponse error"+fragment);
                             }
                     	}else if("text/disconnect-notice".equals(contentType)){
                     		InboundEvent event = new DisconnectEvent();
                     		dispatcher.dispatchEvent(event);
                     	}else if("text/event-plain".equals(contentType)){
                     		InboundEvent event = buildEvent(fragment);
                            if (event != null)
                            {
                                dispatcher.dispatchEvent(event);
                            }
                            else
                            {
                                logger.debug("Ingnore Event:"+buffer.get("Event-Name"));
                            }
                     	}else if("auth/request".equals(contentType)){
                     		
                     	}else{
                     		 logger.error("Inbound Socket read error!Not support contentType:"+contentType);
                     	}
                		 
                		 fragment.clear();
                	 }
                	 bufferLength = 0;
                	 buffer.clear();
                }
                
            }
            this.dead = true;
            logger.debug("Reached end of stream, terminating reader.");
        }
        catch (IOException e)
        {
            this.terminationException = e;
            this.dead = true;
            logger.info("Terminating reader thread: " + e.getMessage());
        }
        finally
        {
            this.dead = true;
            DisconnectEvent disconnectEvent = new DisconnectEvent();
            dispatcher.dispatchEvent(disconnectEvent);
        }

	}
	}
	
	
	
	
	private InboundEvent buildEvent(Map<String, String> buffer){
		return eventBuilder.buildEvent(buffer);
	}
	
	private CommandResponse buildResponse(Map<String, String> buffer){
		return responseBuilder.buildResponse(buffer);
	}

}
